import { Container } from "../Container";
import { BaseGui } from "../Services/BaseGui";
import { EventHandler, HelperTool } from "../Services/Common";
import { DataService } from "../Services/DataService";
import { MarkupItem, MarkupManService } from "../Services/MarkupManService";
import { ViewerService } from "../Services/ViewerService";

export class MarkupManGui extends BaseGui {
    title = `标记管理[${MarkupManGui.name}]`;
    ViewerService = Container.defineProperty(ViewerService);
    DataService = Container.defineProperty(DataService);
    MarkupManService = Container.defineProperty(MarkupManService);
    private getApi() {
        return this.MarkupManService.getApi();
    }
    private getData() {
        return this.MarkupManService.getData();
    }
    SelectChanged = new EventHandler();
    getSelect(): MarkupItem | undefined {
        return undefined;
    }
    Init(): void {
        this.DataService.OnDataChanged.addEventListener(() => {
            this.Refresh();
            this.updateViewer();
        });
        this.MarkupManService.OnItemClick = (item) => {
            alert(item.name);
        };
    }
    async UpdateGui() {
        let fun = {
            enable: true,
            _enableChanged: () => {
                this.MarkupManService.enable = fun.enable;
                this.MarkupManService.updateViewer();
            },
            add: () => {
                let data = this.getData();
                data.items.push({ name: "新标记" + data.items.length, visible: true, color: [255, 0, 0], connect: false, face: false, anchorValue: new Array<number[]>() });
                this.updateViewer();

                fun.data = data.items.length - 1;
                updateGUI();
                fun._dataChange();
            },
            addBySelect: async () => {
                let result = HelperTool.SelectMany(this.ViewerService.viewer.getAllModels(), (m) => {
                    return m.selector.getSelection().map(_ => this.createSpace(m, _));
                });
                let datas = await Promise.all(result);
                let data = this.getData();
                data.items.push(...datas);
                this.updateViewer();

                fun.data = data.items.length - 1;
                updateGUI();
                fun._dataChange();
            },
            addOneBySelect: async () => {
                let data = this.getData();

                let result = HelperTool.SelectMany(this.ViewerService.viewer.getAllModels(), (m) => {
                    return m.selector.getSelection().map(_ => this.getBox(m, _));
                });
                if (result.length == 0)
                    return;
                let box = result[0];
                result.forEach(_ => {
                    box = box.union(_);
                });
                let newItem = this.createLine(`新标记${data.items.length}`, box);
                data.items.push(newItem);

                this.updateViewer();

                fun.data = data.items.length - 1;
                updateGUI();
                fun._dataChange();
            },
            remove: () => {
                if (!window.confirm("确实要清除选中项吗？"))
                    return;
                let data = this.getData();
                data.items.splice(fun.data, 1);
                this.updateViewer();

                fun.data = fun.data < data.items.length ? fun.data : fun.data - 1;
                updateGUI();
                fun._dataChange();
            },
            clear: () => {
                if (!window.confirm("确实要清除所有？"))
                    return;
                this.getData().items = [];
                this.updateViewer();

                fun.data = -1;
                updateGUI();
                fun._dataChange();
            },
            focus: () => {
                let array = this.getData().items;
                let data = array[fun.data];
                this.selectItem(data);
            },
            data: -1,
            dataName: "",

            _dataOptions: () => {
                let array = this.getData().items;
                let options = {} as any;
                array.forEach((v, i) => {
                    const name = `[${i + 1}]${v.name}`;
                    options[name] = i;
                });
                return options;
            },
            _dataChange: () => {
                let data = this.getData();
                let item = data.items[fun.data];
                fun.dataName = item.name;
                updateGUI();
                this.SelectChanged.dispatchEvent();
            },
            _dataNameChanged: () => {
                let array = this.getData().items;
                let data = array[fun.data];
                data.name = fun.dataName;
                this.updateViewer();
                updateGUI();
            }
        }
        this.getSelect = () => {
            let temp = this.getData();
            return temp.items[fun.data];
        }
        let gui = this.gui;
        let updateGUI = () => {
            Array.from(gui.__controllers).forEach(_ => {
                gui.remove(_);
            })
            this.guiService.buildGUIByObject(this.gui, fun);
        }
        updateGUI();
    }
    async createSpace(model: Sippreep.Viewing.Model, dbId: number): Promise<MarkupItem> {
        const fa = new Float32Array(6);
        model.getInstanceTree().getNodeBox(dbId, fa);
        let box = new THREE.Box3(new THREE.Vector3(fa[0], fa[1], fa[2]), new THREE.Vector3(fa[3], fa[4], fa[5]));
        // let size = box.size();
        // box.min.sub(size);
        // box.max.add(size);
        //设置颜色
        const colors = [[255, 0, 0]//红
            , [0, 255, 0]//绿
            , [0, 0, 255]//蓝
        ]
        //box.max.z + 0.01
        let z = box.max.z + 0.01;
        const anchorValue = [
            //[(box.max.x + box.min.x) / 2, (box.max.y + box.min.y) / 2, z],
            [box.max.x, box.max.y, z],
            [box.max.x, box.min.y, z],
            [box.min.x, box.min.y, z],
            [box.min.x, box.max.y, z],
        ]
        //面
        // const anchorValue1 = [
        //     //[(box.max.x + box.min.x) / 2, (box.max.y + box.min.y) / 2, z)],
        //     [box.max.x, box.max.y, z],
        //     [box.max.x, box.min.y, z],
        //     [box.min.x, box.min.y, z],
        //     [box.min.x, box.max.y, z],
        //     [box.max.x, box.max.y, z],
        // ]
        let name = `dbId:${dbId}`;
        // let name = await new Promise<string>((s, f) => {
        //     model.getProperties(dbId, (r) => {
        //         let t = r.properties.find(_ => _.attributeName == "文字")?.displayValue as string;
        //         s(t);
        //     })
        // });
        return { name, visible: true, color: colors[dbId % 3], face: false, connect: true, anchorValue };
    }
    createLine(name: string, box: THREE.Box3): MarkupItem {
        //设置颜色
        // const colors = [[255, 0, 0]//红
        //     , [0, 255, 0]//绿
        //     , [0, 0, 255]//蓝
        // ]
        //box.max.z + 0.01
        let z = box.max.z + 0.01;
        const anchorValue = [
            [box.max.x, box.max.y, z],
            [box.max.x, box.min.y, z],
            [box.min.x, box.min.y, z],
            [box.min.x, box.max.y, z],
        ]
        return { name, visible: true, color: [255, 0, 0], face: false, connect: true, anchorValue };
    }
    private getBox(model: Sippreep.Viewing.Model, dbId: number) {
        const fa = new Float32Array(6);
        model.getInstanceTree().getNodeBox(dbId, fa);
        return new THREE.Box3(new THREE.Vector3(fa[0], fa[1], fa[2]), new THREE.Vector3(fa[3], fa[4], fa[5]));
    }

    async updateViewer() {
        return this.MarkupManService.updateViewer();
    }
    private async selectItem(temp: MarkupItem) {
        this.MarkupManService.selectItem(temp);
    }

}
export class MarkupEditGui extends BaseGui {
    title = `标记编辑[${MarkupEditGui.name}]`;
    ViewerService = Container.defineProperty(ViewerService);
    MarkupManGui = Container.defineProperty(MarkupManGui);
    async getPickPoint() {
        let viewer = await this.ViewerService.ViewerPromise;
        return await viewer.loadExtension("Sippreep.Extensions.PickPoint.PickPointExtension", {}) as any as Sippreep.Extensions.PickPoint.PickPointExtension;
    }
    getSelect() {
        return this.MarkupManGui.getSelect()!;
    }
    OnPickPoint(v: THREE.Vector3) {
    }
    Init(): void {
        this.MarkupManGui.SelectChanged.addEventListener(() => {
            this.Refresh();
        });
        this.getPickPoint().then(api => {
            api.registerPointCallback((v3) => {
                /**
                * 防止与碰撞物体重叠
                */
                const t = this.ViewerService.viewer.navigation.getEyeVector().normalize();
                // 选取点的时候，"反弹""缩短"指定绝对值
                const pickScale: number = 0.05 / 2;
                let v = v3.sub(t.multiplyScalar(pickScale));
                this.OnPickPoint(v);
            });
        });
    }

    UpdateGui(): void {
        let fun = {
            visible: true,
            color: [255, 255, 255],
            connect: false,
            face: false,
            _visibleChange: () => {
                if (!this.getSelect())
                    return;
                this.getSelect().visible = fun.visible;
                this.MarkupManGui.updateViewer();
            },
            _colorChange: () => {
                if (!this.getSelect())
                    return;
                this.getSelect().color = fun.color;
                this.MarkupManGui.updateViewer();
            },
            _connectChange: () => {
                if (!this.getSelect())
                    return;
                this.getSelect().connect = fun.connect;
                this.MarkupManGui.updateViewer();
            },
            _faceChange: () => {
                if (!this.getSelect())
                    return;
                this.getSelect().face = fun.face;
                this.MarkupManGui.updateViewer();
            },
            PickStart: async () => {
                let api = await this.getPickPoint();
                api.enableMode();
                this.OnPickPoint = (v) => {
                    if (!this.getSelect())
                        return;
                    let data = this.getSelect();
                    data.anchorValue.push(v.toArray());
                    this.MarkupManGui.updateViewer();
                }
            },
            PickEnd: () => {
                this.ViewerService.viewer.setActiveNavigationTool("orbit");
            },
            DelPick: () => {
                let data = this.getSelect();
                data.anchorValue.pop();
                this.MarkupManGui.updateViewer();
            }
        }

        let data = this.getSelect();
        if (data) {
            for (let key in fun) {
                //@ts-ignore
                if (data[key] != undefined) {
                    //@ts-ignore
                    fun[key] = data[key];
                }
            }
        }

        let gui = this.gui;
        let updateGUI = () => {
            Array.from(gui.__controllers).forEach(_ => {
                gui.remove(_);
            })
            this.guiService.buildGUIByObject(gui, fun);
        }
        updateGUI();
    }
}
